###
### Makefile of GNU `make', for single source directory project
### Author: zeroxia <zeroxia{at}gmail{dot}com>
### Copyright (c) 2010, 2011
###

CONFIG_MK		:= config.mk
-include $(CONFIG_MK)

TARGET_LIB		?= libfoobar.a
TARGET_PATH		?=
TARGET			= $(if $(TARGET_PATH),\
				   $(TARGET_PATH)/$(TARGET_LIB),$(TARGET_LIB))

TEST_COMM_CSRCS	=
TEST_EXEC_CSRCS	= $(filter-out $(TEST_COMM_CSRCS),$(wildcard test_*.c))

TEST_COMM_CXXSRCS =
TEST_EXEC_CXXSRCS = $(filter-out $(TEST_COMM_CXXSRCS),$(wildcard test_*.cpp))

TEST_CSRCS		= $(TEST_EXEC_CSRCS) $(TEST_COMM_CSRCS)
TEST_CXXSRCS	= $(TEST_EXEC_CXXSRCS) $(TEST_COMM_CXXSRCS)

TEST_TARGET		= $(TEST_EXEC_CSRCS:.c=) $(TEST_EXEC_CXXSRCS:.cpp=)
TEST_COMM_OBJS	= $(TEST_COMM_CSRCS:.c=.o) $(TEST_COMM_CXXSRCS:.cpp=.o)
TEST_OBJS		= $(TEST_CSRCS:.c=.o) $(TEST_CXXSRCS:.cpp=.o)

CSRCS			= $(filter-out $(TEST_CSRCS),$(wildcard *.c))
CXXSRCS			= #$(filter-out $(TEST_CXXSRCS),$(wildcard *.cpp))
ALLSRCS			= $(strip $(TEST_CSRCS) $(TEST_CXXSRCS) $(CSRCS) $(CXXSRCS))
OBJS			= $(CSRCS:.c=.o) $(CXXSRCS:.cpp=.o)

### Toolchain
BINUTIL_PATH	?= /usr/bin
BINUTIL_PREFIX	?=

CC				= $(BINUTIL_PATH)/$(BINUTIL_PREFIX)gcc
CXX				= $(BINUTIL_PATH)/$(BINUTIL_PREFIX)g++
CPP				= $(BINUTIL_PATH)/$(BINUTIL_PREFIX)cpp
LD				= $(BINUTIL_PATH)/$(BINUTIL_PREFIX)ld
OBJCOPY			= $(BINUTIL_PATH)/$(BINUTIL_PREFIX)objcopy
OBJDUMP			= $(BINUTIL_PATH)/$(BINUTIL_PREFIX)objdump
SIZE			= $(BINUTIL_PATH)/$(BINUTIL_PREFIX)size
AR				= $(BINUTIL_PATH)/$(BINUTIL_PREFIX)ar
NM				= $(BINUTIL_PATH)/$(BINUTIL_PREFIX)nm
RANLIB			= $(BINUTIL_PATH)/$(BINUTIL_PREFIX)ranlib
STRIP			= $(BINUTIL_PATH)/$(BINUTIL_PREFIX)strip
SIZE			= $(BINUTIL_PATH)/$(BINUTIL_PREFIX)size

ifeq (,$(strip $(CXXSRCS) $(TEST_CXXSRCS)))
LINKER			?= $(CC)
else
LINKER			?= $(CXX)
endif

### Compilation settings

## Macros
CDEFS			+= -D_THREAD_SAFE -D_REENTRANT

CDEFS			+= -D_LARGEFILE64_SOURCE
CDEFS			+= -D_FILE_OFFSET_BITS=64

## Add the following two defines (appropriately) if needed
#CDEFS			+= -D_POSIX_C_SOURCE=(1,2,199309L,199506L,200112L)
#CDEFS			+= -D_XOPEN_SOURCE=(500,600,700)
CDEFS			+= -D_BSD_SOURCE -D_POSIX_SOURCE -D_ISOC99_SOURCE

ifneq ($(NO_DEBUG), YES)
CDEFS			+= -DMY_DEBUG
else
CDEFS			+= -DNDEBUG
endif

# `DEFAULT_DEBUG_LEVEL' macro intentionally set indepentently from `MY_DEBUG'
ifdef DEFAULT_DEBUG_LEVEL
CDEFS			+= -DDEFAULT_DEBUG_LEVEL=$(DEFAULT_DEBUG_LEVEL)
endif

CDEFS			+= $(ARCH_CDEFS)

## Includes
INCLS			+= -Iinclude
INCLS			+= $(ARCH_INCLS)

## Warnings
COMM_WARNS		+= -Wall -W -Wformat=2
COMM_WARNS		+= -Wpointer-arith \
				   -Wswitch -Wshadow -Wwrite-strings \
				   -Wcast-qual -Wcast-align \
				   -Winline -Wundef

CWARNS			= $(COMM_WARNS) \
				  -Wstrict-prototypes -Wmissing-prototypes \
				  -Wnested-externs

CWARNS			+= -Wredundant-decls -Wpointer-sign

CXXWARNS		= $(COMM_WARNS)
CXXWARNS		+= -Wredundant-decls

CWARNS			+= $(ARCH_CWARNS)
CXXWARNS		+= $(ARCH_CXXWARNS)

ifneq (NO_CWARN_ERROR, YES)
CWARNS			+= -Werror
endif
ifneq (NO_CXXWARN_ERROR, YES)
CXXWARNS		+= -Werror
endif

## Linker flags
LDCFLAGS		= -O2 -fno-common
ifneq ($(NO_DEBUG_SYMBOLS), YES)
LDCFLAGS		+= -g
endif
LDCFLAGS		+= -fdiagnostics-show-option
LDCFLAGS		+= $(ARCH_LDCFLAGS)

## LD paths
LDPATHS			+= -Llib
LDPATHS			+= $(ARCH_LDPATHS)

LDLIBS_SYS		+= -lm -lpthread
#LDLIBS_SYS		+= -lrt

### Final flags for implicit rules

ARFLAGS			= r
CFLAGS			+= $(CDEFS) $(INCLS) $(CWARNS) $(LDCFLAGS) $(ARCH_CLFAGS)
CXXFLAGS		+= $(CDEFS) $(INCLS) $(CXXWARNS) $(LDCFLAGS) $(ARCH_CXXFLAGS)
LDFLAGS			+= $(LDPATHS) $(LDCFLAGS) $(ARCH_LDFLAGS)
LDLIBS			+= $(ARCH_LDLIBS)

### Rules

.PHONY: all test clean cleandep cleanall distclean env setup

CLEAN_GOALS		= clean cleandep cleanall distclean env setup
DEPEND_GOAL		?= .depend
TAGBUILD_OPT	?= tagbuild.opt
TO_DISTCLEAN	?= tags cscope.out cscope.po.out cscope.in.out

all: $(TARGET)

ifeq (,$(strip $(OBJS)))
$(TARGET): ; $(AR) $(ARFLAGS) $(TARGET)
else
$(TARGET): $(TARGET)($(OBJS))
	$(RANLIB) $@
endif

test: $(TEST_TARGET)

$(TEST_TARGET): test_%: test_%.o $(TEST_COMM_OBJS) $(TARGET)
	$(LINKER) $(LDFLAGS) $^ \
		-Xlinker --start-group $(LDLIBS) -Xlinker --end-group \
		$(LDLIBS_SYS) -o $@

tellenc: tellenc.cpp
	$(CXX) $(CXXFLAGS) $(LDFLAGS) $^ -o $@

clean:
	$(RM) $(TARGET) $(TEST_TARGET) $(OBJS) $(TEST_OBJS) tellenc

cleandep:
	$(RM) $(DEPEND_GOAL)

cleanall: clean cleandep

distclean: cleanall
	$(RM) $(TAGBUILD_OPT) $(TO_DISTCLEAN)
ifneq (,$(TARGET_PATH))
	[ ! -d $(TARGET_PATH) ] || [ "`ls -A $(TARGET_PATH)`" ] || \
		rmdir $(TARGET_PATH)
endif

env:
	@echo CSRCS: $(CSRCS)
	@echo CXXSRCS: $(CXXSRCS)
	@echo OBJS: $(OBJS)
	@echo CFLAGS: $(CFLAGS)
	@echo CXXFLAGS: $(CXXFLAGS)
	@echo LDLIBS: $(LDLIBS)
	@echo LDLIBS_SYS: $(LDLIBS_SYS)
	@echo LDFLAGS: $(LDFLAGS)

setup: $(TAGBUILD_OPT)
ifneq (,$(TARGET_PATH))
	[ -d $(TARGET_PATH) ] || mkdir -p $(TARGET_PATH)
endif

ifneq (,$(ARCH_INCLS))
$(TAGBUILD_OPT): Makefile $(CONFIG_MK)
	echo $(ARCH_INCLS) \
		| sed -e "s/ /\n/g" >$@
$(CONFIG_MK): ;
else
$(TAGBUILD_OPT): ;
endif

$(DEPEND_GOAL): $(ALLSRCS)
ifneq (,$(ALLSRCS))
	$(CC) -MM -E $(CDEFS) $(INCLS) $^ >$@
else
	touch $@
endif

#ifneq (,$(strip $(CSRCS)))
#	$(CC) -MM -E $(CDEFS) $(INCLS) $(CSRCS) $(TEST_CSRCS) >$@
#else
#	>$@
#endif
#ifneq (,$(strip $(CXXSRCS) $(TEST_CXXSRCS)))
#	$(CXX) -MM -E $(CDEFS) $(INCLS) $(CXXSRCS) $(TEST_CXXSRCS) >>$@
#endif

ifneq (,$(strip $(if $(MAKECMDGOALS),\
		$(filter-out $(CLEAN_GOALS),$(MAKECMDGOALS)),all)))
-include $(DEPEND_GOAL)
endif

#### MODIFICATION HISTORY
#    Modified: Wed Feb  9 01:43:34 CST 2011
#    Modified: Tue Feb 22 19:17:08 CST 2011
#    Modified: Sun Mar 20 14:24:21 CST 2011
#    Modified: Sun Mar 20 23:17:39 CST 2011
#    Modified: Mon Apr 11 18:47:05 CST 2011
#              for distribution to the public domain
